package org.packtracker.server.servlet;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;

import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
import org.packtracker.client.NotLoggedInException;
import org.packtracker.client.Package;
import org.packtracker.client.PersistenceService;
import org.packtracker.server.PMF;
import org.packtracker.server.Parser;
import org.packtracker.server.model.PersistentDate;
import org.packtracker.server.model.PersistentPackage;
import org.packtracker.server.service.ServiceFactory;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class PersistenceServiceImpl extends RemoteServiceServlet implements PersistenceService {

	private static final Logger LOG = Logger.getLogger(PersistenceServiceImpl.class.getName());

	private Mapper mapper = new DozerBeanMapper();

	@SuppressWarnings("unchecked")
	public List<Package> readPackages(boolean filter) throws NotLoggedInException {

		UserService userService = UserServiceFactory.getUserService();
		checkLoggedIn(userService);

		PersistenceManager persistenceManager = getPersistenceManager();
		List<Package> packages = new ArrayList<Package>();

		try {
			// Create query
			String query = "select from " + PersistentPackage.class.getName();
			if (filter) {
				query += " where mailRecipient == '" + userService.getCurrentUser().getEmail() + "'";
			}
			query += " order by creationDate desc";

			// Fetch package list
			List<PersistentPackage> persistentPackages = (List<PersistentPackage>) persistenceManager.newQuery(query).execute();
			Iterator<PersistentPackage> iter = persistentPackages.iterator();
			while (iter.hasNext()) {
				Package newPackage = mapper.map(iter.next(), Package.class);
				packages.add(newPackage);
			}
		} finally {
			persistenceManager.close();
		}

		return packages;
	}

	public Package addPackage(String trackingId, String tracker) throws NotLoggedInException {

		UserService userService = UserServiceFactory.getUserService();
		checkLoggedIn(userService);

		PersistenceManager persistenceManager = getPersistenceManager();

		PersistentPackage persistentPackage;
		Package newPackage;

		try {

			persistentPackage = new PersistentPackage(trackingId, userService.getCurrentUser().getEmail(), tracker, new Date());

			Parser parser = new Parser();
			parser.parseTracker(persistentPackage);

			persistenceManager.makePersistent(persistentPackage);

			newPackage = mapper.map(persistentPackage, Package.class);

			LOG.log(Level.INFO, "User " + userService.getCurrentUser().getNickname() + " added package with ID " + persistentPackage.getTrackingId());
		} finally {
			persistenceManager.close();
		}

		return newPackage;
	}

	public void removePackage(Long packageId) throws NotLoggedInException {

		UserService userService = UserServiceFactory.getUserService();
		checkLoggedIn(userService);

		PersistenceManager persistenceManager = getPersistenceManager();

		try {
			PersistentPackage persistentPackage = persistenceManager.getObjectById(PersistentPackage.class, packageId);

			LOG.log(Level.INFO, "User " + userService.getCurrentUser().getNickname() + " removed package with ID " + persistentPackage.getTrackingId());

			persistenceManager.deletePersistent(persistentPackage);
		} finally {
			persistenceManager.close();
		}

	}

	@SuppressWarnings("unchecked")
	public Date readLastCheckedDate() {
		PersistenceManager persistenceManager = getPersistenceManager();
		List<PersistentDate> persistentDates;

		try {
			String query = "select from " + PersistentDate.class.getName();
			persistentDates = (List<PersistentDate>) persistenceManager.newQuery(query).execute();
			if (persistentDates.size() > 0) {
				return persistentDates.get(0).getLastCheckedDate();
			}
		} finally {
			persistenceManager.close();
		}
		return null;
	}

	private void checkLoggedIn(UserService userService) throws NotLoggedInException {
		if (userService.getCurrentUser() == null) {
			LOG.log(Level.WARNING, "Attempted RPC without being logged in.");
			throw new NotLoggedInException("Not logged in.");
		}
	}

	private PersistenceManager getPersistenceManager() {
		return PMF.get().getPersistenceManager();
	}

	public List<String> getTrackerNames() {
		return ServiceFactory.getTrackerService().getTrackerNames();
	}
}